From bcc5e475fcc9ddab3a0c436ea097f1de793a7f7e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 13 Aug 2020 14:19:13 -0400 Subject: [PATCH] gtk-demo: Do markup parsing incrementally too Pango has a markup parser api, might as well use it to keep things responsive. --- demos/gtk-demo/fontify.c | 97 ++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/demos/gtk-demo/fontify.c b/demos/gtk-demo/fontify.c index 2b9db1d728..f4115352d5 100644 --- a/demos/gtk-demo/fontify.c +++ b/demos/gtk-demo/fontify.c @@ -167,6 +167,10 @@ insert_tags_for_attributes (GtkTextBuffer *buffer, typedef struct { + GMarkupParseContext *parser; + char *markup; + gsize pos; + gsize len; GtkTextBuffer *buffer; GtkTextIter iter; GtkTextMark *mark; @@ -178,9 +182,11 @@ typedef struct static void free_markup_data (MarkupData *mdata) { + g_free (mdata->markup); + g_clear_pointer (&mdata->parser, g_markup_parse_context_free); gtk_text_buffer_delete_mark (mdata->buffer, mdata->mark); - pango_attr_iterator_destroy (mdata->attr); - pango_attr_list_unref (mdata->attributes); + g_clear_pointer (&mdata->attr, pango_attr_iterator_destroy); + g_clear_pointer (&mdata->attributes, pango_attr_list_unref); g_free (mdata->text); g_object_unref (mdata->buffer); g_free (mdata); @@ -225,51 +231,94 @@ insert_markup_idle (gpointer data) return G_SOURCE_REMOVE; } -static void -insert_markup (GtkTextBuffer *buffer, - GtkTextIter *iter, - const char *markup, - int len) +static gboolean +parse_markup_idle (gpointer data) { - char *text; - PangoAttrList *attributes; + MarkupData *mdata = data; + gint64 begin; GError *error = NULL; - MarkupData *data; - g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + begin = g_get_monotonic_time (); - if (!pango_parse_markup (markup, len, 0, &attributes, &text, NULL, &error)) + do { + if (g_get_monotonic_time () - begin > G_TIME_SPAN_MILLISECOND) + { + g_idle_add (parse_markup_idle, data); + return G_SOURCE_REMOVE; + } + + if (!g_markup_parse_context_parse (mdata->parser, + mdata->markup + mdata->pos, + MIN (4096, mdata->len - mdata->pos), + &error)) + { + g_warning ("Invalid markup string: %s", error->message); + g_error_free (error); + free_markup_data (mdata); + return G_SOURCE_REMOVE; + } + + mdata->pos += 4096; + } while (mdata->pos < mdata->len); + + if (!pango_markup_parser_finish (mdata->parser, + &mdata->attributes, + &mdata->text, + NULL, + &error)) { g_warning ("Invalid markup string: %s", error->message); g_error_free (error); - return; + free_markup_data (mdata); + return G_SOURCE_REMOVE; } - if (!attributes) + if (!mdata->attributes) { - gtk_text_buffer_insert (buffer, iter, text, -1); - g_free (text); - return; + gtk_text_buffer_insert (mdata->buffer, &mdata->iter, mdata->text, -1); + free_markup_data (mdata); + return G_SOURCE_REMOVE; } - data = g_new (MarkupData, 1); + mdata->attr = pango_attr_list_get_iterator (mdata->attributes); + insert_markup_idle (data); + + return G_SOURCE_REMOVE; +} + +/* Takes a ref on @buffer while it is operating, + * and consumes @markup. + */ +static void +insert_markup (GtkTextBuffer *buffer, + GtkTextIter *iter, + char *markup, + int len) +{ + MarkupData *data; + + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + + data = g_new0 (MarkupData, 1); data->buffer = g_object_ref (buffer); data->iter = *iter; - data->attributes = attributes; - data->text = text; + data->markup = markup; + data->len = len; + + data->parser = pango_markup_parser_new (0); + data->pos = 0; /* create mark with right gravity */ data->mark = gtk_text_buffer_create_mark (buffer, NULL, iter, FALSE); - data->attr = pango_attr_list_get_iterator (attributes); - insert_markup_idle (data); + parse_markup_idle (data); } static void -fontify_finish (GObject *source, +fontify_finish (GObject *source, GAsyncResult *result, - gpointer data) + gpointer data) { GSubprocess *subprocess = G_SUBPROCESS (source); GtkTextBuffer *buffer = data; -- 2.30.2